/**************************************************************************************************
	$Header: /pub/cvsroot/mydns/src/mydns/task.c,v 1.5 2002/07/07 06:16:59 bboy Exp $
	task.c: Routines for processing and dealing with tasks.

	Copyright (C) 2002  Don Moore <bboy@bboy.net>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at Your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

#include "named.h"

extern time_t task_timeout;


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	DESCTASK
	Describe a task; used by error/warning output.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char *
desctask(t)
	TASK *t;
{
	static char desc[1024];

	snprintf(desc, sizeof(desc), "[%llu] %s: %s %s", t->internal_id, inet_ntoa(t->addr.sin_addr),
		mydns_qtype_str(t->qtype), t->qname ? (char *)t->qname : "<NONE>");
	return (desc);
}
/*--- desctask() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	TASK_INIT
	Allocates and initializes a new task, and returns a pointer to it.
	t = task_init(NEED_ZONE, SOCKTYPE_UDP, fd, &addr);
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
TASK *
task_init(status, fd, socktype, addr)
	taskstat_t status;			/* Initial status */
	int fd;							/* Associated file descriptor for socket */
	tasksocktype_t socktype;	/* Socket type (SOCKTYPE_UDP or SOCKTYPE_TCP) */
	struct sockaddr_in *addr;	/* Remote address */
{
	TASK *new;

	new = CALLOC(1, sizeof(TASK));
	new->status = status;
	new->fd = fd;
	new->socktype = socktype;
	memcpy(&new->addr, addr, sizeof(struct sockaddr_in));
	new->internal_id = Status.requests;
	new->timeout = time(NULL) + task_timeout;

	return (new);
}
/*--- task_init() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	TASK_FREE
	Free the memory used by a task.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
task_free(t)
	TASK *t;
{
	register int n;

	numlist_free(t->Cnames);
	for (n = 0; n < t->numNames; n++)
		free(t->Names[n]);
	if (t->numNames)
		free(t->Names);
	free(t->Offsets);
	free(t->qd);
	rrlist_free(&t->an);
	rrlist_free(&t->ns);
	rrlist_free(&t->ar);
	if (t->rdata)
		free(t->rdata);
	if (t->reply)
		free(t->reply);
	free(t);
}
/*--- task_free() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	TASK_INIT_HEADER
	Sets and/or clears header fields and values as necessary.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
task_init_header(t)
	TASK *t;
{
	t->hdr.qr = 1;					/* This is the response, not the query */
	t->hdr.ra = 0;					/* Recursion is NOT available (this may change in the future) */
	t->hdr.rcode = DNS_R_OK;	/* Assume success unless told otherwise */
}
/*--- task_init_header() ------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	TASK_PROCESS
	Process the specified task, if possible.  Returns a pointer to the next task.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
TASK *
task_process(t)
	TASK *t;
{
	TASK *next;

	Assert(t);
	next = t->next;

	/* Dequeue timed out task */
	if (current_time > t->timeout)
	{
		Status.timedout++;
		dequeue(Tasks, t, 1);
		return (next);
	}

	/* Process task if necessary */
	if (t->status == NEED_ANSWER)
	{
		resolve(t, ANSWER, t->qtype, t->qname);
		build_reply(t);
		t->status = NEED_SEND;
	}

	if (t->status == NEED_SEND)
	{
		switch (t->socktype)
		{
			case SOCKTYPE_UDP:
				write_udp_reply(t);
				break;

			default:
				Warnx("%s: %d: %s", desctask(t), (int)t->socktype, _("socket type not supported"));
				dequeue(Tasks, t, 1);
				break;
		}
	}

	return (next);
}
/*--- task_process() ----------------------------------------------------------------------------*/

/* vi:set ts=3: */
/* NEED_PO */
